#pragma once
#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#include <cassert>

#define qmax 5

template <class T>
class Ringqueue
{
public:
    Ringqueue():_max(qmax),_ppos(0), _cpos(0)
    {
        _rq.resize(_max);

        pthread_mutex_init(&_pmutex, nullptr);
        pthread_mutex_init(&_cmutex, nullptr);

        int n = sem_init(&_psem, 0, _max);
        assert(n == 0);
        n = sem_init(&_csem, 0, 0);
        assert(n == 0);
        (void*)n;
    }

    void rq_push(const T& val)
    {
        sem_wait(&_psem);
        pthread_mutex_lock(&_pmutex);
        _ppos %= _max;
        _rq[_ppos++] = val;
        sem_post(&_csem);
        pthread_mutex_unlock(&_pmutex);
    }

    void rq_pop(T& reval)
    {
        sem_wait(&_csem);
        pthread_mutex_lock(&_cmutex);
        _cpos %= _max;
        reval = _rq[_cpos++];
        sem_post(&_psem);
        pthread_mutex_unlock(&_cmutex);
    }

    ~Ringqueue()
    {
        pthread_mutex_destroy(&_pmutex);
        pthread_mutex_destroy(&_cmutex);

        sem_destroy(&_psem);
        sem_destroy(&_csem);
    }

private:
    std::vector<T> _rq;
    int _max;   //最大存储
    int _ppos;   //生产者当前存储位置
    int _cpos;   //生产者当前存储位置

    pthread_mutex_t _pmutex;
    pthread_mutex_t _cmutex;

    sem_t _psem;
    sem_t _csem;
};